package andev.lopengles2airhockey;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import andev.aandroidlib.util.AOpenGLES2;
import andev.aandroidlib.util.FileOperator;

/**
 * @author Angus
 *         the GL10 instance passed in is referred to as glUnused.
 *         We don't use this when drawing using OpenGL ES 2; instead,
 *         we use the static methods of the class GLES20.
 *         The GL10 parameter is only there because the same interface is used for OpenGL ES 1.x.
 */
public class AirHockeyRenderer implements Renderer {
    private static final String U_COLOR = "u_Color";
    private static final String A_POSITION = "a_Position";
    private final int BYTES_PER_FLOAT = 4;
    private final Context context;
    private FloatBuffer vertexData;
    private float[] tableVertices =
            {
                    // Triangle1
                    -0.5f, -0.5f,
                    0.5f, 0.5f,
                    -0.5f, 0.5f,

                    // Triangle2
                    -0.5f, -0.5f,
                    0.5f, -0.5f,
                    0.5f, 0.5f,

                    //Line in center
                    -0.5f, 0f,
                    0.5f, 0f,

                    //Mallets
                    0f, -0.25f,
                    0f, 0.25f
            };
    private int programID;
    private int uColorLocation;
    private int aPositionLocation;
    public AirHockeyRenderer(Context context) {
        this.context = context;
        vertexData = ByteBuffer.allocateDirect(tableVertices.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();

        //Once I allocate the memory for the vertices,I need to initialize this memory with float[] vertices
        vertexData.put(tableVertices);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Set the background clear color to gray.
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        //Shader code
        FileOperator fileOperator = new FileOperator();
        String vertexShaderCode = fileOperator.getStreamText(context.getResources().openRawResource(R.raw.vertex_shader));
        String fragmentShaderCode = fileOperator.getStreamText(context.getResources().openRawResource(R.raw.fragment_shader));

        //Compile shader
        int vertexShader = AOpenGLES2.compileShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = AOpenGLES2.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        //LinkProgram,An OpenGL program is simply one vertex shader and one fragment shader linked together into a single object
        programID = AOpenGLES2.linkProgram(vertexShader, fragmentShader);
        GLES20.glUseProgram(programID);

        //We call glGetUniformLocation() to get the location of our uniform, and we store that location in uColorLocation. We’ll use that when we want to update the value of this uniform later on.
        uColorLocation = GLES20.glGetUniformLocation(programID, U_COLOR);

        //We call glGetAttribLocation() to get the location of our attribute. With this location, we’ll be able to tell OpenGL where to find the data for this attribute.
        aPositionLocation = GLES20.glGetAttribLocation(programID, A_POSITION);
        //We then call glVertexAttribPointer() to tell OpenGL that it can find the data for a_Position in the buffer vertexData
        /* int index, This is the attribute location, and we pass in aPositionLocation
         * int size, This is the data count per attribute, or how many components are associated with each vertex for this attribute
         * int type, This is the type of data. We defined our data as a list of floating point values, so we pass in GL_FLOAT
         * boolean normalized, This only applies if we use integer data, so we can safely ignore it for now.
         * int stride, the stride,applies when we store more than one attribute in a single array
         * Buffer ptr, This tells OpenGL where to read data
         */
        vertexData.position(0);
        GLES20.glVertexAttribPointer(aPositionLocation, 2, GLES20.GL_FLOAT, false, 0, vertexData);
        //After set up the attribute pointer we need to enable it
        GLES20.glEnableVertexAttribArray(aPositionLocation);
    }

    /*
     * This is called whenever the surface changes; for example, when switching from portrait to landscape. It is also called after the surface has been created.
     */
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    /*
     * This is called whenever it's time to draw a new frame.
     */
    @Override
    public void onDrawFrame(GL10 gl) {
        //fill the screen with the color previously defined by our call to glClearColor()
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);


        /*Here Start drawing*/

        //Table(2Triangle)
        //First we update the value of u_Color in our shader code by calling glUniform4f().
        GLES20.glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);

        //Once we’ve specified the color, we then draw our table with a call to glDrawArrays to draw from array's data
        // The first argument tells OpenGL that we want to draw triangles. To draw triangles, we need to pass in at least three vertices per triangle. The second argument tells OpenGL to read in vertices starting at the beginning of our vertex array, and the third argument tells OpenGL to read in six vertices.
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);

        //Line in center
        GLES20.glUniform4f(uColorLocation, 1, 0, 0, 1);
        GLES20.glDrawArrays(GLES20.GL_LINES, 6, 2);

        //First mallet
        GLES20.glUniform4f(uColorLocation, 0, 0, 1, 1);
        GLES20.glDrawArrays(GLES20.GL_POINTS, 8, 1);

        //Second mallet
        GLES20.glUniform4f(uColorLocation, 1, 0, 0, 1);
        GLES20.glDrawArrays(GLES20.GL_POINTS, 9, 1);
    }

}
